<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>src/node/class.node.js - sceneGraph.js</title>
    <link rel="stylesheet" href="http://yui.yahooapis.com/3.9.1/build/cssgrids/cssgrids-min.css">
    <link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css">
    <link rel="stylesheet" href="../assets/css/main.css" id="site_styles">
    <link rel="shortcut icon" type="image/png" href="../assets/favicon.png">
    <script src="http://yui.yahooapis.com/combo?3.9.1/build/yui/yui-min.js"></script>
</head>
<body class="yui3-skin-sam">

<div id="doc">
    <div id="hd" class="yui3-g header">
        <div class="yui3-u-3-4">
            
                <h1><img src="../../logo/logoCGSG_256x57.png" title="sceneGraph.js"></h1>
            
        </div>
        <div class="yui3-u-1-4 version">
            <em>API Docs for: v2.1.0</em>
        </div>
    </div>
    <div id="bd" class="yui3-g">

        <div class="yui3-u-1-4">
            <div id="docs-sidebar" class="sidebar apidocs">
                <div id="api-list">
    <h2 class="off-left">APIs</h2>
    <div id="api-tabview" class="tabview">
        <ul class="tabs">
            <li><a href="#api-classes">Classes</a></li>
            <li><a href="#api-modules">Modules</a></li>
        </ul>

        <div id="api-tabview-filter">
            <input type="search" id="api-filter" placeholder="Type to filter APIs">
        </div>

        <div id="api-tabview-panel">
            <ul id="api-classes" class="apis classes">
            
                <li><a href="../classes/CGSG.html">CGSG</a></li>
            
                <li><a href="../classes/CGSGAccordion.html">CGSGAccordion</a></li>
            
                <li><a href="../classes/CGSGAnimationManager.html">CGSGAnimationManager</a></li>
            
                <li><a href="../classes/CGSGAnimationMethod.html">CGSGAnimationMethod</a></li>
            
                <li><a href="../classes/CGSGBindEntry.html">CGSGBindEntry</a></li>
            
                <li><a href="../classes/CGSGButtonMode.html">CGSGButtonMode</a></li>
            
                <li><a href="../classes/CGSGCollisionGhostOnDemandTester.html">CGSGCollisionGhostOnDemandTester</a></li>
            
                <li><a href="../classes/CGSGCollisionManager.html">CGSGCollisionManager</a></li>
            
                <li><a href="../classes/CGSGCollisionMethod.html">CGSGCollisionMethod</a></li>
            
                <li><a href="../classes/CGSGCollisionRegionTester.html">CGSGCollisionRegionTester</a></li>
            
                <li><a href="../classes/CGSGCollisionTesterFactory.html">CGSGCollisionTesterFactory</a></li>
            
                <li><a href="../classes/CGSGColor.html">CGSGColor</a></li>
            
                <li><a href="../classes/CGSGCSSManager.html">CGSGCSSManager</a></li>
            
                <li><a href="../classes/CGSGDimension.html">CGSGDimension</a></li>
            
                <li><a href="../classes/CGSGEvent.html">CGSGEvent</a></li>
            
                <li><a href="../classes/CGSGEventManager.html">CGSGEventManager</a></li>
            
                <li><a href="../classes/CGSGHandleBox.html">CGSGHandleBox</a></li>
            
                <li><a href="../classes/CGSGImgManager.html">CGSGImgManager</a></li>
            
                <li><a href="../classes/CGSGInterpolator.html">CGSGInterpolator</a></li>
            
                <li><a href="../classes/CGSGInterpolatorLinear.html">CGSGInterpolatorLinear</a></li>
            
                <li><a href="../classes/CGSGInterpolatorTCB.html">CGSGInterpolatorTCB</a></li>
            
                <li><a href="../classes/CGSGKeyFrame.html">CGSGKeyFrame</a></li>
            
                <li><a href="../classes/CGSGMap.html">CGSGMap</a></li>
            
                <li><a href="../classes/CGSGMask.html">CGSGMask</a></li>
            
                <li><a href="../classes/CGSGMaskCache.html">CGSGMaskCache</a></li>
            
                <li><a href="../classes/CGSGMaskClip.html">CGSGMaskClip</a></li>
            
                <li><a href="../classes/CGSGMath.html">CGSGMath</a></li>
            
                <li><a href="../classes/CGSGNode.html">CGSGNode</a></li>
            
                <li><a href="../classes/CGSGNodeButton.html">CGSGNodeButton</a></li>
            
                <li><a href="../classes/CGSGNodeCircle.html">CGSGNodeCircle</a></li>
            
                <li><a href="../classes/CGSGNodeColorPicker.html">CGSGNodeColorPicker</a></li>
            
                <li><a href="../classes/CGSGNodeCurveTCB.html">CGSGNodeCurveTCB</a></li>
            
                <li><a href="../classes/CGSGNodeDomElement.html">CGSGNodeDomElement</a></li>
            
                <li><a href="../classes/CGSGNodeEllipse.html">CGSGNodeEllipse</a></li>
            
                <li><a href="../classes/CGSGNodeImage.html">CGSGNodeImage</a></li>
            
                <li><a href="../classes/CGSGNodeLine.html">CGSGNodeLine</a></li>
            
                <li><a href="../classes/CGSGNodeSlider.html">CGSGNodeSlider</a></li>
            
                <li><a href="../classes/CGSGNodeSliderHandle.html">CGSGNodeSliderHandle</a></li>
            
                <li><a href="../classes/CGSGNodeSprite.html">CGSGNodeSprite</a></li>
            
                <li><a href="../classes/CGSGNodeSquare.html">CGSGNodeSquare</a></li>
            
                <li><a href="../classes/CGSGNodeTabMenu.html">CGSGNodeTabMenu</a></li>
            
                <li><a href="../classes/CGSGNodeText.html">CGSGNodeText</a></li>
            
                <li><a href="../classes/CGSGNodeWebview.html">CGSGNodeWebview</a></li>
            
                <li><a href="../classes/CGSGParticle.html">CGSGParticle</a></li>
            
                <li><a href="../classes/CGSGParticleEmitter.html">CGSGParticleEmitter</a></li>
            
                <li><a href="../classes/CGSGParticleSystem.html">CGSGParticleSystem</a></li>
            
                <li><a href="../classes/CGSGPickNodeMethod.html">CGSGPickNodeMethod</a></li>
            
                <li><a href="../classes/CGSGPosition.html">CGSGPosition</a></li>
            
                <li><a href="../classes/CGSGRegion.html">CGSGRegion</a></li>
            
                <li><a href="../classes/CGSGRotation.html">CGSGRotation</a></li>
            
                <li><a href="../classes/CGSGScale.html">CGSGScale</a></li>
            
                <li><a href="../classes/CGSGSceneGraph.html">CGSGSceneGraph</a></li>
            
                <li><a href="../classes/CGSGSection.html">CGSGSection</a></li>
            
                <li><a href="../classes/CGSGTimeline.html">CGSGTimeline</a></li>
            
                <li><a href="../classes/CGSGTraverser.html">CGSGTraverser</a></li>
            
                <li><a href="../classes/CGSGVector2D.html">CGSGVector2D</a></li>
            
                <li><a href="../classes/CGSGView.html">CGSGView</a></li>
            
                <li><a href="../classes/CGSGWEBVIEWMODE.html">CGSGWEBVIEWMODE</a></li>
            
                <li><a href="../classes/CGSGWrapMode.html">CGSGWrapMode</a></li>
            
                <li><a href="../classes/GLOBAL_CONSTANTS.html">GLOBAL_CONSTANTS</a></li>
            
                <li><a href="../classes/GLOBAL_METHODS.html">GLOBAL_METHODS</a></li>
            
                <li><a href="../classes/GLOBAL_PROPERTIES.html">GLOBAL_PROPERTIES</a></li>
            
                <li><a href="../classes/UTIL_ARRAY.html">UTIL_ARRAY</a></li>
            
                <li><a href="../classes/WUICCGSGNodeImageFactory.html">WUICCGSGNodeImageFactory</a></li>
            
            </ul>

            <ul id="api-modules" class="apis modules">
            
                <li><a href="../modules/Animation.html">Animation</a></li>
            
                <li><a href="../modules/Collision.html">Collision</a></li>
            
                <li><a href="../modules/Math.html">Math</a></li>
            
                <li><a href="../modules/Node.html">Node</a></li>
            
                <li><a href="../modules/ParticleSystem.html">ParticleSystem</a></li>
            
                <li><a href="../modules/Scene.html">Scene</a></li>
            
                <li><a href="../modules/Util.html">Util</a></li>
            
            </ul>
        </div>
    </div>
</div>

            </div>
        </div>
        <div class="yui3-u-3-4">
                <div id="api-options">
        Show:
        <label for="api-show-inherited">
            <input type="checkbox" id="api-show-inherited" checked>
            Inherited
        </label>

        <label for="api-show-protected">
            <input type="checkbox" id="api-show-protected">
            Protected
        </label>

        <label for="api-show-private">
            <input type="checkbox" id="api-show-private">
            Private
        </label>
        <label for="api-show-deprecated">
            <input type="checkbox" id="api-show-deprecated">
            Deprecated
        </label>

    </div>


            <div class="apidocs">
                <div id="docs-main">
                    <div class="content">
                        <h1 class="file-heading">File: src/node/class.node.js</h1>

<div class="file">
    <pre class="code prettyprint linenums">
/*
 * Copyright (c) 2014 Gwennael Buchet
 *
 * License/Terms of Use
 *
 * Permission is hereby granted, free of charge and for the term of intellectual property rights on the Software, to any
 * person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), to use, copy, modify
 * and propagate free of charge, anywhere in the world, all or part of the Software subject to the following mandatory conditions:
 *
 *   •    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 *  Any failure to comply with the above shall automatically terminate the license and be construed as a breach of these
 *  Terms of Use causing significant harm to Gwennael Buchet.
 *
 *  THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 *  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
 *  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 *  Except as contained in this notice, the name of Gwennael Buchet shall not be used in advertising or otherwise to promote
 *  the use or other dealings in this Software without prior written authorization from Gwennael Buchet.
 *
 *  These Terms of Use are subject to French law.
 */

/**
 * Base class for a Node in the Scene Graph.
 * Each node encapsulates its position, dimension, scale and rotation, ...
 * @class CGSGNode
 * @extends CGSGObject
 * @module Node
 * @main Node
 * @constructor
 * @param {Number} x Relative position on X
 * @param {Number} y Relative position on Y
 * @type {CGSGNode}
 * @author Gwennael Buchet (gwennael.buchet@gmail.com)
 */
var CGSGNode = CGSGObject.extend(
    {
        initialize: function (x, y) {

            /**
             * The name of this nodes. Should be unique, but no control is done.
             * @property name
             * @default &quot;&quot;
             * @type {String}
             */
            this.name = &quot;&quot;;
            /**
             * Indicate whether this node is selected or not.
             * Use CGSGView::scenegraph.selectNode(nodeToSelect) to select a node
             * @property isSelected
             * @readonly
             * @default false
             * @type {Boolean}
             */
            this.isSelected = false;
            /**
             * The type of this class. Must be redefined by inherited classes
             * @property classType
             * @readonly
             * @type {String}
             */
            this.classType = &quot;CGSGNODE&quot;;

            /**
             * The 8 handleboxes that will be the resize handles
             * the resize handles will be in this order:
             *  0  1  2
             *  3     4
             *  5  6  7
             * @property handles
             * @readonly
             * @type {Array}
             */
            this.handles = [];

            /**
             * Level of transparency of the node.
             * @default 1.0
             * @property globalAlpha
             * @type {Number}
             */
            this.globalAlpha = 1.0;
            /**
             * Indicate if the node is visible (and so selectable) or not
             * @property isVisible
             * @default true
             * @type {Boolean}
             */
            this.isVisible = true;

            /**
             * If true, the node will be proportionally resized
             * @property isProportionalResize
             * @type {Boolean}
             */
            this.isProportionalResize = false;

            /**
             * Set to true if the node can&#x27;t be resized only in height or width
             * @property isProportionalResizeOnly
             * @default false
             * @type {boolean}
             */
            this.isProportionalResizeOnly = false;

            /**
             * Define the method the detection (or &quot;pick&quot;) method will be used for this node.
             * Possible values CGSGPickNodeMethod.REGION and CGSGPickNodeMethod.GHOST.
             *
             * &lt;ul&gt;
             *     &lt;li&gt;REGION : the detection returns true if the mouse cursor is inside the bounding box of the node&lt;/li&gt;
             *     &lt;li&gt;GHOST : the detection will use the &quot;renderGhost&quot; method of the node to achieve a more accurate detection&lt;/li&gt;
             * &lt;/ul&gt;
             *
             * @property pickNodeMethod
             * @default CGSGPickNodeMethod.REGION
             * @type {CGSGPickNodeMethod}
             */
            this.pickNodeMethod = CGSGPickNodeMethod.REGION;

            /**
             * List of the children (empty if this nodes is a leaf)
             * @property children
             * @readonly
             * @type {Array}
             */
            this.children = [];

            /**
             * The constraint region when moving the node
             * @property regionConstraint
             * @default null
             * @type {null}
             */
            this.regionConstraint = null;

            /**
             * Node defining constraint region when moving the node
             * @property nodeConstraint
             * @default null
             * @type {null}
             */
            this.nodeConstraint = null;
            /**
             * List of nodes which are constraint to the region of this one
             * @property _followers
             * @type {Array}
             * @private
             */
            this._followers = [];

            /**
             * Pivot point to apply a rotation.
             * The point is a value between [0, 0] and [1, 1].
             * [0, 0] is the top left corner of the bounding box and [1, 1] the bottom right corner.
             * @property rotationCenter
             * @default null
             * @type {CGSGPosition}
             */
            this.rotationCenter = new CGSGPosition(0.5, 0.5);

            /**
             * can be fulfilled by the developer to put in whatever he needs
             * @property userData
             * @default {} Empty object
             * @type {*}
             */
            this.userData = {};

            /**
             * selection attributes
             * If true, this node is clickable and so will be checked by the pickNode function
             * @property isClickable
             * @default true
             * @type {Boolean}
             */
            this.isClickable = true;
            /**
             * If true, this node can be resized by the user. In that case, the dimension property will be affected, not the scale one.
             * @property isResizable
             * @default false
             * @type {Boolean}
             */
            this.isResizable = false;
            /**
             * If true, the node can be dragged by the user
             * @property isDraggable
             * @default false
             * @type {Boolean}
             */
            this.isDraggable = false;

            /**
             * If true, the absolute matrix will be recomputed after each movement (and so in animation).
             * Set it to false to gain performance if you don&#x27;t need to keep trace of absolute position (no need to collision, picknode, ...)
             * @property needToKeepAbsoluteMatrix
             * @default true
             * @type {Boolean}
             */
            this.needToKeepAbsoluteMatrix = true;

            /**
             * Color for the line around this node when selected
             * @property selectionLineColor
             * @default &quot;#FF6890&quot;
             * @type {String}
             */
            this.selectionLineColor = null;
            /**
             * Width for the line around this node when selected
             * @property selectionLineWidth
             * @default 2
             * @type {Number}
             */
            this.selectionLineWidth = null;
            /**
             * Color for the handle boxes around this node when selected
             * @property handleSize
             * @type {Number}
             */
            this.handleSize = null;
            /**
             * Color for the handle boxes around this node when selected
             * @property handleColor
             * @type {String}
             */
            this.handleColor = null;

            /**
             * Updated by the scene itself. Don&#x27;t update it manually.
             * True if the mice is over the node, false otherwise
             * @property isMouseOver
             * @readonly
             * @type {Boolean}
             */
            this.isMouseOver = false;
            /**
             * Updated by the scene itself. Don&#x27;t update it manually.
             * True if the node is being moved manually, false otherwise
             * @property isMoving
             * @readonly
             * @type {Boolean}
             */
            this.isMoving = false;
            /**
             * Updated by the scene itself. Don&#x27;t update it manually.
             * True if the node is being resized manually, false otherwise
             * @property isResizing
             * @readonly
             * @type {Boolean}
             */
            this.isResizing = false;

            /**
             * ID for the node. Should be filled by the developer. The framework will never use it.
             * @property _id
             * @type {Number}
             * @private
             */
            this._id = 0;
            /**
             * parent of this node
             * @property _parentNode
             * @type {CGSGNode}
             * @private
             */
            this._parentNode = null;

            this._isCached = false;
            //fake canvas to pre-render static display
            this._cacheCanvas = null;
            this._cacheCtx = null;

            /**
             * @property shadowOffsetX
             * @default 0
             * @type {number}
             */
            this.shadowOffsetX = 0;
            /**
             * @property shadowOffsetY
             * @default 0
             * @type {number}
             */
            this.shadowOffsetY = 0;
            /**
             * @property shadowBlur
             * @default 0
             * @type {number}
             */
            this.shadowBlur = 0;
            /**
             * @property shadowColor
             * @default &quot;#333333&quot;
             * @type {string}
             */
            this.shadowColor = &quot;#333333&quot;;

            /**
             * Relative position of this nodes on the canvas container, relatively to the position of its parent node.
             * Never use it to move the node, use translateBy/translateWith/translateTo instead
             * @readonly
             * @property position
             * @default CGSGPosition(0, 0)
             * @type {CGSGPosition}
             */
            this.position = new CGSGPosition(0, 0);
            /**
             * Absolute position of this nodes on the canvas container. Generated value. Don&#x27;t modify it manually
             * Never use it to move the node, use translateBy/translateWith/translateTo instead
             * @readonly
             * @property _absPos
             * @private
             * @type {CGSGPosition}
             */
            this._absPos = new CGSGPosition(0, 0);
            /**
             * Dimension of this nodes on the canvas container
             * Never use it to resize the node, use resizeBy/resizeWith/resizeTo instead
             * @readonly
             * @property dimension
             * @default CGSGDimension(0, 0)
             * @type {CGSGDimension}
             */
            this.dimension = new CGSGDimension(0, 0);
            /**
             * Relative scale of this nodes on the canvas container, relatively to the scale of its parent node.
             * Never use it to scale or resize the node, use scaleBy/scaleWith/scaleTo instead
             * @readonly
             * @property scale
             * @default CGSGScale(1, 1)
             * @type {CGSGScale}
             */
            this.scale = new CGSGScale(1, 1);
            /**
             * Absolute scale of this nodes on the canvas container. Generated value. Don&#x27;t modify it manually
             * Never use it to scale the node, use scaleBy/scaleWith/scaleTo instead
             * @readonly
             * @property _absSca
             * @private
             * @type {CGSGScale}
             */
            this._absSca = new CGSGScale(1, 1);
            /**
             * Relative rotation of this nodes on the canvas container, relatively to the rotation of its parent node.
             * Never use it to rotate or resize the node, use rotateBy/rotateWith/rotateTo instead
             * @readonly
             * @property rotation
             * @default CGSGRotation(0)
             * @type {CGSGRotation}
             */
            this.rotation = new CGSGRotation(0);
            /**
             * Absolute rotation of this nodes on the canvas container. Generated value. Don&#x27;t modify it manually
             * Never use it to rotate or resize the node, use rotateBy/rotateWith/rotateTo instead
             * @readonly
             * @private
             * @property _absRot
             * @type {CGSGRotation}
             */
            this._absRot = new CGSGRotation(0);

            /**
             * @property _isDrag
             * @type {Boolean}
             * @private
             */
            this._isDrag = false;

            /**
             * true if this node is traversable (recursively) (ie : by the picknode, a traverser, ...)
             * @property isTraversable
             * @type {Boolean}
             */
            this.isTraversable = true;

            /**
             * Indicate if this node is managed by the collision manager
             * @property isCollisionManaged
             * @type {Boolean}
             */
            this.isCollisionManaged = false;

            /**
             * Callback on mouse over the node
             * @property onMouseOver
             * @default null
             * @type {function}
             *
             * @example
             *  this.onMouseOver = function (event) {
             *      event.data.node; //CGSGNode
             *      event.data.position; //Array of CGSGPosition
             *      event.data.nativeEvent; //Event
             *  }
             */
            this.onMouseOver = null;
            /**
             * Callback on mouse enter on the node
             * @property onMouseEnter
             * @default null
             * @type {function}
             *
             * @example
             *  this.onMouseEnter = function (event) {
             *      event.data.node; //CGSGNode
             *      event.data.position; //Array of CGSGPosition
             *      event.data.nativeEvent; //Event
             *  }
             */
            this.onMouseEnter = null;
            /**
             * Callback on mouse out
             * @property onMouseOut
             * @default null
             * @type {function}
             *
             * @example
             *  this.onMouseOut = function (event) {
             *      event.data.node; //CGSGNode
             *      event.data.position; //Array of CGSGPosition
             *      event.data.nativeEvent; //Event
             *  }
             */
            this.onMouseOut = null;
            /**
             * Callback on mouse up
             * @property onMouseUp
             * @default null
             * @type {function}
             *
             * @example
             *  this.onMouseUp = function (event) {
             *      event.data.node; //CGSGNode
             *      event.data.position; //Array of CGSGPosition
             *      event.data.nativeEvent; //Event
             *  }
             */
            this.onMouseUp = null;
            /**
             * Callback on mouse or touch click
             * @property onClick
             * @default null
             * @type {function}
             *
             * @example
             *  this.onClick = function (event) {
             *      event.data.node; //CGSGNode
             *      event.data.position; //Array of CGSGPosition
             *      event.data.nativeEvent; //Event
             *  }
             */
            this.onClick = null;
            /**
             * Callback on mouse or touch double click
             * @property onDblClick
             * @default null
             * @type {function}
             *
             * @example
             *  this.onDblClick = function (event) {
             *      event.data.node; //CGSGNode
             *      event.data.position; //Array of CGSGPosition
             *      event.data.nativeEvent; //Event
             *  }
             */
            this.onDblClick = null;
            /**
             * Callback on drag this node
             * @property onDrag
             * @default null
             * @type {function}
             *
             * @example
             *  this.onDrag = function (event) {
             *      event.data.node; //CGSGNode
             *      event.data.position; //Array of CGSGPosition
             *      event.data.nativeEvent; //Event
             *  }
             */
            this.onDrag = null;
            /**
             * Callback on end of drag this node
             * @property onDragEnd
             * @default null
             * @type {function}
             *
             * @example
             *  this.onDragEnd = function (event) {
             *      event.data.node; //CGSGNode
             *      event.data.position; //Array of CGSGPosition
             *      event.data.nativeEvent; //Event
             *  }
             */
            this.onDragEnd = null;
            /**
             * Callback on resize this node
             * @property onResize
             * @default null
             * @type {function}
             *
             * @example
             *  this.onResize = function (event) {
             *      event.data.node; //CGSGNode
             *      event.data.position; //Array of CGSGPosition
             *      event.data.nativeEvent; //Event
             *  }
             */
            this.onResize = null;
            /**
             * Callback on end resize this node
             * @property onResizeEnd
             * @default null
             * @type {function}
             *
             * @example
             *  this.onResizeEnd = function (event) {
             *      event.data.node; //CGSGNode
             *      event.data.position; //Array of CGSGPosition
             *      event.data.nativeEvent; //Event
             *  }
             */
            this.onResizeEnd = null;
            /**
             * Callback on select this node
             * @property onSelect
             * @default null
             * @type {function}
             *
             * @example
             *  this.onSelect = function (event) {
             *      event.data.node; //CGSGNode
             *      event.data.position; //Array of CGSGPosition
             *      event.data.nativeEvent; //Event
             *  }
             */
            this.onSelect = null;

            /**
             * Callback on deselect this node
             * @property onDeselect
             * @default null
             * @type {function}
             *
             * @example
             *  this.onDeselect = function (event) {
             *      event.data.node; //CGSGNode
             *      event.data.position; //Array of CGSGPosition
             *      event.data.nativeEvent; //Event
             *  }
             */
            this.onDeselect = null;

            /**
             * Callback on when a child is removed
             * @property onChildRemove
             * @default null
             * @type {function}
             *
             * @example
             *  this.onDeselect = function (event) {
             *      event.data.node; //CGSGNode
             *      event.data.position; //Array of CGSGPosition
             *      event.data.nativeEvent; //Event
             *  }
             */
            this.onChildRemove = null;

            /**
             * Callback before the node is rendered, children included
             * @property onBeforeRender
             * @default null
             * @type {function}
             * */
            this.onBeforeRender = null;
            /**
             * Callback after the scene is rendered
             * @property onAfterRender
             * @default null
             * @type {function}
             * */
            this.onAfterRender = null;
            /**
             * @property onAfterRenderStart
             * @default null
             * @type {function}
             * */
            this.onAfterRenderStart = null;
            /**
             * Callback fired while translating
             * @property onTranslate
             * @default null
             * @type {function}
             * */
            this.onTranslate = null;

            /**
             * Threshold applied when detecting selection. Defalt value is picked from CGSG.globalDetectSelectionThreshold.
             * Value could be changed after.
             *
             * @property detectSelectionThreshold
             * @type {Number}
             * @example
             * var n = new CGSGNode(10, 10);
             * n.detectSelectionThreshold = 10; // node will be picked in an area [0, 0, 30, 30] (x, y, w, h)
             */
            this.detectSelectionThreshold = CGSG.globalDetectSelectionThreshold;

            /**
             * Array of colors to fill the background of the node. Will be overrided with CSS content.
             * CGSGNode extensions should (but not mandatory) use this attribute
             *
             * CSS managed.
             * @property bkgcolors
             * @type {Array}
             */
            this.bkgcolors = [];

            /**
             * Color to stroke the node. Will be overrided with CSS content
             * CGSGNode extensions should (but not mandatory) use this attribute as the stroke color for their node
             *
             * CSS managed.
             * @property lineColor
             * @type {String}
             */
            this.lineColor = null;
            /**
             * Width of the line that stroke the node. Will be overrided with CSS content.
             * CGSGNode extensions should (but not mandatory) use this attribute as the strokeWidth for their node
             * Let 0 if you don&#x27;t want to stroke the node.
             *
             * CSS managed.
             * @property lineWidth
             * @default 0
             * @type {Number}
             */
            this.lineWidth = 0;

            /**
             * Corner radius. Used by only few official nodes and maybe by some community&#x27;s nodes.
             *
             * CSS managed.
             *
             * @property borderRadius
             * @type {number}
             * @default 0
             */
            this.borderRadius = 0;

            this._cls = [];
            this._clsBBox = null;
            this.setClass(&quot;cgsgnode&quot;);
            this.setClassBBox(&quot;cgsgnode-bbox&quot;);

            //initialize the position and dimension
            this.translateTo(x, y, true);
            this.dimension.width = 0;
            this.dimension.height = 0;

            /**
             * Set to true if dimension of the node is not the original one anymore
             * @property _isDimensionChanged
             * @default false
             * @private
             */
            this._isDimensionChanged = false;

            // initialize the selection handleBoxes
            for (var i = 0; i &lt; 8; i++) {
                var handleBox = new CGSGHandleBox(this, this.handleSize, this.handleColor,
                                                  this.selectionLineColor, this.selectionLineWidth, 0, 0);
                this.handles.push(handleBox);
            }

            this.computeAbsoluteMatrix(true);
        },

        /**
         * @method moveLocalZIndex
         * @param s {Number} step
         */
        moveLocalZIndex: function (s) {
            var i = this.getLocalZIndex();

            if (!isNaN(i)) {
                this.setLocalZIndex(this.getLocalZIndex() + s);
            }
        },

        /**
         * @method setLocalZIndex
         * @param i {Number} index
         */
        setLocalZIndex: function (i) {
            if (cgsgExist(this._parentNode)) {
                i = Math.max(0, Math.min(CGSGMath.fixedPoint(i), this._parentNode.children.length - 1));

                var n = this.getLocalZIndex();
                var p = this._parentNode;

                if (i !== n) {
                    p.detachChild(this);
                    p.addChildAt(this, i);
                }
            }
        },

        setLocalZIndexToLast: function () {
            this.setLocalZIndex(this._parentNode.children.length - 1);
        },

        getLocalZIndex: function () {
            if (!cgsgExist(this._parentNode)) {
                return NaN;
            }

            return this._parentNode.children.indexOf(this);
        },

        /**
         * return the relative region of this node
         * @public
         * @method getRegion
         * @return {CGSGRegion}
         */
        getRegion: function () {
            return new CGSGRegion(this.position.x, this.position.y, this.getWidth(), this.getHeight());
        },

        /**
         * return the absolute region of this node
         * @public
         * @method getAbsoluteRegion
         * @return {CGSGRegion}
         */
        getAbsoluteRegion: function () {
            return new CGSGRegion(this.getAbsLeft(), this.getAbsTop(), this.getAbsWidth(),
                                  this.getAbsHeight());
        },

        //// RENDERING MANIPULATION //////

        /**
         * Wipes the canvas context
         * @method _clearContext
         * @param c {?} context
         * @param w {Number} canvasWidth
         * @param h {Number} canvasHeight
         * @private
         */
        _clearContext: function (c, w, h) {
            c.clearRect(0, 0, w, h);
        },

        /**
         * Use this method to make the node precomputed or not.
         * If it&#x27;s precomputed, it won&#x27;t be redraw every frame, but only when the &quot;invalidate&quot; method is called.
         * @method setPrecomputed
         * @param p {Boolean} isPrecomputed
         */
        setPrecomputed: function (p) {
            this._isCached = p;
            this.invalidate();
        },

        /**
         * Force the redraw of the node if it&#x27;s precomputed
         * @method invalidate
         */
        invalidate: function () {
            if (this._isCached) {
                this._preCompute();
            }
        },

        /**
         * Reload theme (colors, ...) from loaded CSS file
         * To be overrided
         * @method invalidateTheme
         *
         */
        invalidateTheme: function () {

            //Use of &quot;this._cls&quot; class names which define the current CSS classes used by this object.
            var fs = CGSG.cssManager.getAttrInArray(this._cls, &quot;background&quot;);//&quot;background-color&quot;);
            var lw = CGSG.cssManager.getAttrInArray(this._cls, &quot;border-width&quot;);
            var ss = CGSG.cssManager.getAttrInArray(this._cls, &quot;border-color&quot;);
            var a = CGSG.cssManager.getFloat(CGSG.cssManager.getAttrInArray(this._cls, &quot;opacity&quot;));
            var r = CGSG.cssManager.getNumber(CGSG.cssManager.getAttrInArray(this._cls, &quot;border-radius&quot;));

            if (cgsgExist(r)) {
                this.borderRadius = r;
            }

            var rgb;

            if (cgsgExist(fs)) {
                //value is given as &quot;rgb(xx, yy, zz)&quot;. Let&#x27;s convert it to hex
                rgb = CGSGColor.fromString(fs);
                if (cgsgExist(rgb.r) &amp;&amp; cgsgExist(rgb.g) &amp;&amp; cgsgExist(rgb.b)) {
                    this.bkgcolors[0] = CGSGColor.rgb2hex(rgb.r, rgb.g, rgb.b);
                }
                else {
                    //value is given as &quot;linear-gradient(rgb(150, 150, 150), rgb(127, 127, 127))&quot;.
                    // Let&#x27;s convert it to 2 hex.
                    var srgb1 = fs.substring(fs.indexOf(&quot;rgb&quot;), fs.indexOf(&quot;)&quot;) + 1);
                    var srgb2 = fs.substring(fs.lastIndexOf(&quot;rgb&quot;), fs.lastIndexOf(&quot;)&quot;));
                    var rgb1 = CGSGColor.fromString(srgb1);
                    var rgb2 = CGSGColor.fromString(srgb2);
                    this.bkgcolors[0] = CGSGColor.rgb2hex(rgb1.r, rgb1.g, rgb1.b);
                    this.bkgcolors[1] = CGSGColor.rgb2hex(rgb2.r, rgb2.g, rgb2.b);
                }

            }
            if (cgsgExist(lw)) {
                this.lineWidth = CGSG.cssManager.getNumber(lw);
            }
            if (cgsgExist(ss)) {
                this.lineColor = ss;
            }

            //avoid to override previous value if no one was defined
            if (cgsgExist(a)) {
                this.globalAlpha = a;
            }

            if (cgsgExist(this._clsBBox)) {
                var sc = CGSG.cssManager.getAttr(this._clsBBox, &quot;background-color&quot;);
                var sw = CGSG.cssManager.getNumber(CGSG.cssManager.getAttr(this._clsBBox, &quot;border-width&quot;));
                var slc = CGSG.cssManager.getAttr(this._clsBBox, &quot;outline-color&quot;);
                var slw = CGSG.cssManager.getNumber(CGSG.cssManager.getAttr(this._clsBBox, &quot;outline-width&quot;));

                if (cgsgExist(sc)) {
                    this.handleColor = sc;
                }
                if (cgsgExist(sw)) {
                    this.handleSize = sw;
                }
                if (cgsgExist(slc)) {
                    this.selectionLineColor = slc;
                }
                if (cgsgExist(slw)) {
                    this.selectionLineWidth = slw;
                }
            }
        },

        /**
         * Set CSS class for this node (not for bounding box, use &#x27;setClassBBox&#x27; instead).
         * CSS class must define attributes used by this node.
         * @method setClass
         * @param {String} cls
         */
        setClass: function (cls) {
            this._cls = [];
            this._cls.push(cls);
            this.invalidateTheme();

            //todo for v2.1: load only attribute from this class instead of reloading everything
        },

        /**
         * Add CSS class for this node (not for bounding box, use &#x27;setClassBBox&#x27; instead).
         * CSS class must define attributes used by this node.
         * @method addClass
         * @param {String} cls
         */
        addClass: function (cls) {
            this._cls.push(cls);
            this.invalidateTheme();
        },

        /**
         * remove CSS class for this node (not for bounding box, use &#x27;setClassBBox&#x27; instead).
         * @method removeClass
         * @param {String} cls
         */
        removeClass: function (cls) {
            this._cls = this._cls.without(cls);
            this.invalidateTheme();
        },

        /**
         * Set CSS class for the bounding box of this node (not for node itself, use &#x27;setClass&#x27; instead).
         * CSS class must define attributes used by BBox.
         * @method setClassBBox
         * @param {String} cls
         */
        setClassBBox: function (cls) {
            this._clsBBox = cls;
            this.invalidateTheme();
        },

        /**
         * @method _applyShadow
         * @param c {CanvasRenderingContext2D}
         * @private
         */
        _applyShadow: function (c) {
            if (this.shadowOffsetX !== 0 || this.shadowOffsetY !== 0) {
                c.shadowOffsetX = this.shadowOffsetX;
                c.shadowOffsetY = this.shadowOffsetY;
                c.shadowBlur = this.shadowBlur;
                c.shadowColor = this.shadowColor;
            }
        },

        /**
         * @method _preCompute
         * @private
         */
        _preCompute: function () {
            if (!cgsgExist(this._cacheCanvas)) {
                this._cacheCanvas = document.createElement(&#x27;canvas&#x27;);
                this._cacheCtx = this._cacheCanvas.getContext(&#x27;2d&#x27;);
            }
            //this._cacheCanvas.width = this.getWidth() + this.shadowOffsetX; //CGSG.canvas.width;
            //this._cacheCanvas.height = this.getHeight() + this.shadowOffsetY; //CGSG.canvas.height;
            cgsgClearContext(this._cacheCtx);

            this._applyShadow(this._cacheCtx);
            this.render(this._cacheCtx);
        },

        /**
         * internal method of the framework that encapsulate all the work aroud the rendering method
         * @method doRender
         * @param c {CanvasRenderingContext2D} context
         * @param t {Boolean} isThemeInvalidated
         */
        doRender: function (c, t) {
            if (t) {
                this.invalidateTheme();
            }

            var ctx = c;

            var startEvt = new CGSGEvent(this, {context: c, node: this});

            if (cgsgExist(this.onBeforeRender)) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_BEFORE_RENDER, startEvt);
                ctx = startEvt.data.context;
                //this.onBeforeRender({context: context});
            }

            //save current state
            this.beforeRender(ctx);

            if (this.globalAlpha &gt; 0) {
                ctx.globalAlpha = this.globalAlpha;

                //todo, if this node is constraint to another one, so check if this bbox is inside constraint node
                /*if (cgsgExist(this.nodeConstraint)) {
                 //compute delta on left, right, top, bottom
                 var dL = this.getAbsLeft() - this.nodeConstraint.getAbsLeft(); //must be &gt;= 0
                 if (dL &lt; 0)
                 this.translateWith(-dL, 0, true);
                 var dT = this.getAbsTop() - this.nodeConstraint.getAbsTop(); //must be &gt;= 0
                 if (dT &lt; 0)
                 this.translateWith(0, -dT, true);
                 var dR = this.nodeConstraint.getAbsRight() - this.getAbsRight(); //must be &gt;= 0
                 if (dR &lt; 0)
                 this.resizeWith(-dR, 0);
                 var dB = this.nodeConstraint.getAbsBottom() - this.getAbsBottom(); //must be &gt;= 0
                 if (dB &lt; 0)
                 this.resizeWith(0, -dB);
                 }*/

                if (this._isCached) {
                    //render the pre-rendered canvas
                    ctx.drawImage(this._cacheCanvas, 0, 0);
                }
                else {
                    if (!cgsgExist(this.bkgcolors[1])) {
                        ctx.fillStyle = this.bkgcolors[0];
                    }
                    else {
                        var gradient = ctx.createLinearGradient(0, 0, 0, this.dimension.height);
                        for (var i = 0, len = this.bkgcolors.length; i &lt; len; i++) {
                            gradient.addColorStop(i, this.bkgcolors[i]);
                        }
                        ctx.fillStyle = gradient;
                    }

                    if (this.lineWidth &gt; 0) {
                        ctx.strokeStyle = this.lineColor;
                        ctx.lineWidth = this.lineWidth;
                    }

                    this._applyShadow(ctx);
                    this.render(ctx);
                }
            }

            if (!CGSG.isBoundingBoxOnTop &amp;&amp; this.isSelected) {
                this.renderBoundingBox(ctx);
            }

            var endEvt = new CGSGEvent(this, {context: ctx, node: this});

            //restore state
            this.afterRender(endEvt.data.context, t);

            if (cgsgExist(this.onAfterRender)) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_AFTER_RENDER, endEvt);
                ctx = endEvt.data.context;
                //this.onAfterRender({context: c});
            }

        },

        /**
         * Empty rendering function. Must be overrided by the inherited classes
         * @method render
         * @param {CanvasRenderingContext2D} context the context into render the node
         * */
        render: function (context) {
        },

        /**
         * internal method of the framework that encapsulate all the work around the ghost rendering method
         * @method doRenderGhost
         * @param c {CanvasRenderingContext2D} ghost Context
         */
        doRenderGhost: function (c) {
            //save current state
            this.beforeRenderGhost(c);

            if (this.globalAlpha &gt; 0) {
                if (this._isCached) {
                    //render the pre-rendered canvas
                    c.drawImage(this._cacheCanvas, 0, 0);
                }
                else {
                    c.fillStyle = this.bkgcolors[0];

                    if (this.lineWidth &gt; 0) {
                        c.strokeStyle = this.lineColor;
                        c.lineWidth = this.lineWidth;
                    }

                    this.renderGhost(c);
                }
            }

            //restore state
            this.afterRenderGhost(c);
        },

        /**
         * Empty ghost rendering function.
         * Render here your custom nodes with a single color (CGSG.ghostColor).
         * This will be used by the SceneGraph to know if the mouse cursor is over this nodes.
         *
         * @method renderGhost
         * @param ghostCtx {CanvasRenderingContext2D} The context for the ghost rendering
         */
        renderGhost: function (ghostCtx) {
            this.render(ghostCtx);
        },

        /**
         * Render the selection box and handle boxes around the bounding box of this node when selected
         * @protected
         * @method renderBoundingBox
         * @param c {CanvasRenderingContext2D} context the context into render the node
         * */
        renderBoundingBox: function (c) {
            //this.computeAbsoluteMatrix(true);

            var w = this.getWidth(), h = this.getHeight();

            if (cgsgExist(this.selectionLineWidth) &amp;&amp; this.selectionLineWidth &gt; 0) {
                c.strokeStyle = this.selectionLineColor;

                c.lineWidth = this.selectionLineWidth / this._absSca.y;
                c.beginPath();
                //top line
                c.moveTo(0, 0);
                c.lineTo(w, 0);
                //bottom line
                c.moveTo(0, h);
                c.lineTo(w, h);
                c.stroke();
                c.closePath();

                c.lineWidth = this.selectionLineWidth / this._absSca.x;
                c.beginPath();
                //left line
                c.moveTo(0, 0);
                c.lineTo(0, h);
                //right line
                c.moveTo(w, 0);
                c.lineTo(w, h);
                c.stroke();
                c.closePath();
            }

            //draw the resize handles
            if (this.isResizable) {
                // draw the handle boxes
                var hx = this.handleSize / (2 * this._absSca.x);
                var hy = this.handleSize / (2 * this._absSca.y);

                // 0  1  2
                // 3     4
                // 5  6  7

                // top left, middle, right
                this.handles[0].translateTo(-hx, -hy);
                this.handles[1].translateTo(w / 2 - hx, -hy);
                this.handles[2].translateTo(w - hx, -hy);

                // middle left
                this.handles[3].translateTo(-hx, h / 2 - hy);

                // middle right
                this.handles[4].translateTo(w - hx, h / 2 - hy);

                // bottom left, middle, right
                this.handles[6].translateTo(w / 2 - hx, h - hy);
                this.handles[5].translateTo(-hx, h - hy);
                this.handles[7].translateTo(w - hx, h - hy);

                if (this.isProportionalResizeOnly) {
                    this.handles[1].isVisible = false;
                    this.handles[3].isVisible = false;
                    this.handles[4].isVisible = false;
                    this.handles[6].isVisible = false;
                }

                var i;
                for (i = 0; i &lt; 8; i++) {
                    this.handles[i].size = this.handleSize;
                    this.handles[i].fillColor = this.handleColor;
                    this.handles[i].strokeColor = this.selectionLineColor;
                    this.handles[i].lineWidth = this.selectionLineWidth;
                    this.handles[i].render(c);
                }
            }
        },

        /**
         * Must be called before to start the rendering of the nodes
         * @protected
         * @method beforeRender
         * @param c {CanvasRenderingContext2D} context the context into render the nodes
         * */
        beforeRender: function (c) {
            //first save the current c state
            c.save();

            //move the c to the nodes&#x27;s relative position
            c.translate(this.position.x, this.position.y);
            c.scale(this.scale.x, this.scale.y);

            // translate c to center of canvas
            if (cgsgExist(this.rotationCenter)) {
                c.translate(this.dimension.width * this.rotationCenter.x,
                            this.dimension.height * this.rotationCenter.y);
                c.rotate(this.rotation.angle);
                c.translate(-this.dimension.width * this.rotationCenter.x,
                            -this.dimension.height * this.rotationCenter.y);
            }
            else {
                c.rotate(this.rotation.angle);
            }

            if (this.onBeforeRenderEnd) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.BEFORE_RENDER_END,
                                           new CGSGEvent(this, {c: c, node: this}));
            }
        },

        /**
         * Must be called after a render
         * @protected
         * @method afterRender
         * @param c {CanvasRenderingContext2D} The context into render the nodes
         * @param t {Boolean} isThemeInvalidated true if you need to reload theme for children of this node
         * */
        afterRender: function (c, t) {
            if (cgsgExist(this.onAfterRenderStart)) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.AFTER_RENDER_START,
                                           new CGSGEvent(this, {context: c, node: this}));
            }

            //render all children
            if (!this.isALeaf()) {
                //draw children
                for (var i = 0, len = this.children.length; i &lt; len; ++i) {
                    var childNode = this.children[i];
                    if (childNode.isVisible) {
                        childNode.doRender(c, t);
                    }
                }
            }

            //restore the context state
            c.restore();
        },

        /**
         * Must be called before begin to render the nodes in GHOST mode
         * @protected
         * @method beforeRenderGhost
         * @param c {CanvasRenderingContext2D} context the context into render the nodes
         */
        beforeRenderGhost: function (c) {
            //first save the current context state
            c.save();
            //move the context to the nodes&#x27;s relative position
            c.translate(this._absPos.x, this._absPos.y);
            c.rotate(this._absRot.angle);
            c.scale(this._absSca.x, this._absSca.y);
        },

        /**
         * Must be called before begin to render
         * @protected
         * @method afterRenderGhost
         * @param c {CanvasRenderingContext2D} context the context into render the nodes
         * */
        afterRenderGhost: function (c) {
            //restore the context state
            c.restore();
        },

        /**
         * Mark this nodes as selected
         * @method setSelected
         * @param s {Boolean} is Selected
         * */
        setSelected: function (s) {
            this.isSelected = s;
            this._isDrag = true;

            if (s &amp;&amp; this.onSelect !== null) {
                //this.onSelect({node: this});
                CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_SELECT, new CGSGEvent(this, {node: this}));
            }
            else if (this.onDeselect !== null) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_DESELECT, new CGSGEvent(this, {node: this}));
                //this.onDeselect({node: this});
            }
        },

        /**
         * Returns a region which represents the total surface covered by this node and its children too.
         * @protected
         * @method getCompleteRegion
         * @return {CGSGRegion}
         */
        getCompleteRegion: function () {
            return new CGSGRegion(this.getMinAbsoluteLeft(), this.getMinAbsoluteTop(), this.getMaxAbsoluteRight(),
                                  this.getMaxAbsoluteBottom());
        },

        /**
         * Returns a position which represents the lowest position covered between this node and its children too.
         * @protected
         * @method getCompletePosition
         * @return {CGSGPosition}
         */
        getCompletePosition: function () {
            return new CGSGPosition(this.getMinAbsoluteLeft(), this.getMinAbsoluteTop());
        },

        /**
         * Returns a position which represents the highest dimension covered between this node and its children too.
         * @protected
         * @method getCompleteDimension
         * @return {CGSGDimension}
         */
        getCompleteDimension: function () {
            return new CGSGDimension(this.getMaxAbsoluteRight(), this.getMaxAbsoluteBottom());
        },

        /**
         * return this if this nodes is under the mice cursor
         * Can be overrided by inherited klass to optimize this perform.
         * This default function used the ghost rendering method
         * @protected
         * @method detectSelection
         * @param pos {CGSGPosition} mousePosition A CGSGPosition object
         * @param c {CanvasRenderingContext2D} ghost Context
         * @param s {CGSGScale} absoluteScale
         */
        detectSelection: function (pos, c, s) {
            if (this.pickNodeMethod === CGSGPickNodeMethod.REGION) {
                if (pos.x &gt;= this._absPos.x - this.detectSelectionThreshold &amp;&amp;
                    pos.x &lt; this._absPos.x + this.detectSelectionThreshold + this.getWidth() * s.x &amp;&amp;
                    pos.y &gt;= this._absPos.y - this.detectSelectionThreshold &amp;&amp;
                    pos.y &lt; this._absPos.y + this.detectSelectionThreshold + this.getHeight() * s.y) {
                    return this;
                }
            }
            else /*if (this.pickNodeMethod == CGSGPickNodeMethod.GHOST)*/ {

                //todo: is this node is in cache, so check if there is a painted pixel at x,y from getImageData()

                // draw shape onto ghost context
                this.doRenderGhost(c);

                // get image data at the mouse x,y pixel
                var id = c.getImageData(pos.x, pos.y, 1, 1);

                cgsgClearContext(c);

                // if the mouse pixel exists, select this nodes
                if (id.data[0] !== 0 || id.data[1] !== 0 || id.data[2] !== 0) {
                    return this;
                }
            }

            return null;
        },

        /**
         * return this if this nodes is under the region
         * Can be overrided by inherited klass to optimize this perform.
         * This default function used the ghost rendering method
         * @protected
         * @method detectSelectionInRegion
         * @param rg {CGSGRegion} region The region to check
         * @param c {CanvasRenderingContext2D} ghostContext
         */
        detectSelectionInRegion: function (rg, c) {

            //if (this.pickNodeMethod == CGSGPickNodeMethod.REGION) {

            var us = this.getAbsoluteRegion();
            //select this node only if it is totally inside the region
            if (cgsgRegionIsInRegion(us, rg, 0)) {
                return this;
            }

            /*}
             else { //if (this.pickNodeMethod == CGSGPickNodeMethod.GHOST) {
             // draw shape onto ghost context
             this.doRenderGhost(c);

             // get image data at the mouse x,y pixel
             if (!rg.isEmpty()) {
             var id = c.getImageData(rg.position.x, rg.position.y, rg.dimension.width, rg.dimension.height);

             cgsgClearContext(c);

             var len = id.data.length;
             var count = 0;
             // if the a pixel exists in the region then, select this node
             for (var i = 0 ; i &lt; len ; i += 4) {
             if (id.data[i] != 0 || id.data[i + 1] != 0 || id.data[i + 2] != 0) {
             count += 4;
             //return this;
             }
             }
             if (count &gt;= len)
             return this;
             }
             }*/

            return null;
        },

        /**
         * Check if this nodes is under the cursor position.
         * @public
         * @method pickNode
         * @param pos {CGSGPosition} mousePosition position of the mouse on the canvas
         * @param absSca {CGSGScale} absoluteScale a CGSGScale absolute relativeScale of all parents
         * @param c {CanvasRenderingContext2D} ghostContext a copy of the canvas context
         * @param {Boolean} recursively if false, don&#x27;t traverse the children of this nodes
         * @param {Function} condition Condition to be picked
         * ie: &quot;color==&#x27;yellow&#x27;&quot; or &quot;classType==&#x27;CGSGNodeImage&#x27; &amp;&amp; this.globalAlpha&gt;0.5&quot;
         */
        pickNode: function (pos, absSca, c, recursively, condition) {
            var selectedNode = null;
            var childAbsoluteScale = null;
            if (cgsgExist(absSca)) {
                childAbsoluteScale = absSca.multiply(this.scale);
            }
            else {
                childAbsoluteScale = this.getAbsScale(false);
            }

            if (this.isTraversable &amp;&amp; (this.isClickable || this.isResizable || this.isDraggable)) {
                if (!cgsgExist(condition) || condition(this) === true) {
                    this.computeAbsoluteMatrix(false);

                    // First of all, try to to see if resize handler has been picked
                    if (this.isSelected &amp;&amp; this.isResizable) {
                        for (var h = 0; h &lt; 8; h++) {
                            var selectionHandle = this.handles[h];

                            if (selectionHandle.checkIfSelected(pos, CGSG.resizeHandleThreshold)) {
                                return this;
                            }
                        }
                    }

                    selectedNode =
                    this.detectSelection(pos, c, childAbsoluteScale);
                }
            }

            //traverse the children if asked
            if (this.isTraversable &amp;&amp; recursively &amp;&amp; !this.isALeaf()) {
                for (var i = this.children.length - 1; i &gt;= 0; --i) {
                    var childNode = this.children[i];
                    var selectedChild = childNode.pickNode(pos,
                                                           childAbsoluteScale, c,
                                                           recursively, condition);
                    if (cgsgExist(selectedChild)) {
                        selectedNode = selectedChild;
                        break;
                    }
                }

                childAbsoluteScale = null;
            }

            return selectedNode;
        },

        /**
         * Return all nodes (Array) in the given region
         * @public
         * @method pickNodes
         * @param {CGSGRegion} region of the canvas to check
         * @param {CGSGScale} absoluteScale a CGSGScale absolute relativeScale of all parents
         * @param {CanvasRenderingContext2D} ghostContext a copy of the canvas context
         * @param {Boolean} recursively if false, don&#x27;t traverse the children of this nodes
         * @param {Function} condition Condition to be picked
         * ie: &quot;color==&#x27;yellow&#x27;&quot; or &quot;classType==&#x27;CGSGNodeImage&#x27; &amp;&amp; this.globalAlpha&gt;0.5&quot;
         */
        pickNodes: function (region, absoluteScale, ghostContext, recursively, condition) {
            var selectedNodes = [];

            //if (region.dimension.width == 0 &amp;&amp; region.dimension.height == 0)
            if (region.isEmpty()) {
                return selectedNodes;
            }

            var childAbsoluteScale = null;
            if (cgsgExist(absoluteScale)) {
                childAbsoluteScale = absoluteScale.multiply(this.scale);
            }
            else {
                childAbsoluteScale = this.getAbsScale(false);
            }

            if (this.isTraversable &amp;&amp; (/*this.isClickable ||*/ this.isResizable || this.isDraggable)) {
                if (!cgsgExist(condition) || condition(this) === true) {
                    this.computeAbsoluteMatrix(false);
                    var selected = this.detectSelectionInRegion(region, ghostContext);
                    if (cgsgExist(selected)) {
                        selectedNodes.push(selected);
                    }
                }
            }

            //traverse the children if asked
            if (this.isTraversable &amp;&amp; recursively &amp;&amp; !this.isALeaf()) {
                for (var i = this.children.length - 1; i &gt;= 0; --i) {
                    var childNode = this.children[i];
                    var selectedChildren = childNode.pickNodes(region,
                                                               childAbsoluteScale, ghostContext,
                                                               recursively, condition);
                    if (selectedChildren !== null &amp;&amp; selectedChildren !== undefined) {
                        selectedNodes = selectedNodes.concat(selectedChildren);
                    }
                }

                childAbsoluteScale = null;
            }

            return selectedNodes;
        },

        /**
         * Return true if this nodes has no child
         * @method isALeaf
         * */
        isALeaf: function () {
            return this.children.length &lt;= 0;
        },

        //// TRANSFORMATION MANIPULATION //////

        _applyContraintsToFollowers: function () {
            cgsgIterate(this._followers, (function (i, node) {
                //compute delta on left, top, right, bottom
                var dL = node.getAbsLeft() - this.getAbsLeft(); //must be &gt;= 0
                if (dL &lt; 0) {
                    node.translateWith(-dL, 0, true);
                }
                var dT = node.getAbsTop() - this.getAbsTop(); //must be &gt;= 0
                if (dT &lt; 0) {
                    node.translateWith(0, -dT, true);
                }

                var dR = this.getAbsRight() - node.getAbsRight(); //must be &gt;= 0
                if (dR &lt; 0) {
                    //first translate, then resize
                    dL = node.getAbsWidth() - this.getAbsWidth();
                    if (dL &gt; 0) {
                        node.resizeWith(-dL, 0);
                    }
                    else {
                        node.translateWith(dR, 0, true);
                    }

                }
                var dB = this.getAbsBottom() - node.getAbsBottom(); //must be &gt;= 0
                if (dB &lt; 0) {
                    //first translate, then resize
                    dR = node.getAbsHeight() - this.getAbsHeight();
                    if (dR &gt; 0) {
                        node.resizeTo(this.getAbsWidth(), node.getHeight());
                    }
                    else {
                        node.translateWith(0, dB, true);
                    }
                }
            }).bind(this));
        },

        /**
         * Replace current relative position by this new one
         * @method translateTo
         * @param {Number} x
         * @param {Number} y
         * @param {Boolean} computeAbsoluteValue (default: true)
         */
        translateTo: function (x, y, computeAbsoluteValue) {
            this.position.translateTo(x, y);
            if (this.needToKeepAbsoluteMatrix &amp;&amp; computeAbsoluteValue !== false) {
                this._absPos = this.getAbsPosition(true);
            }
            this._applyContraintsToFollowers();

            if (cgsgExist(this.onTranslate)) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_TRANSLATE, new CGSGEvent(this, {node: this}));
            }
        },

        /**
         * Add new coordinate to the current relative one
         * @method translateWith
         * @param {Number} x
         * @param {Number} y
         * @param {Boolean} computeAbsoluteValue (default: true)
         * */
        translateWith: function (x, y, computeAbsoluteValue) {
            this.position.translateWith(x, y);
            if (this.needToKeepAbsoluteMatrix &amp;&amp; computeAbsoluteValue !== false) {
                this._absPos = this.getAbsPosition(true);
            }

            this._applyContraintsToFollowers();
            if (cgsgExist(this.onTranslate)) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_TRANSLATE, new CGSGEvent(this, {node: this}));
            }
        },

        /**
         * Add new coordinate to the current relative one
         * @method translateBy
         * @param {Number} x
         * @param {Number} y
         * @param {Boolean} computeAbsoluteValue (default: true)
         * */
        translateBy: function (x, y, computeAbsoluteValue) {
            this.position.translateBy(x, y);
            if (this.needToKeepAbsoluteMatrix &amp;&amp; computeAbsoluteValue !== false) {
                this._absPos = this.getAbsPosition(true);
            }

            this._applyContraintsToFollowers();
            if (cgsgExist(this.onTranslate)) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_TRANSLATE, new CGSGEvent(this, {node: this}));
            }
        },

        /**
         * Replace current dimension by these new ones
         * @method resizeTo
         * @param {Number} w
         * @param {Number} h
         * */
        resizeTo: function (w, h) {
            this.dimension.resizeTo(w, h);
            this._applyContraintsToFollowers();
            this._endResize();
        },

        /**
         * Multiply current dimension by these new ones
         * @method resizeTBy
         * @param {Number} wf
         * @param {Number} hf
         * */
        resizeBy: function (wf, hf) {
            this.dimension.resizeBy(wf, hf);
            this._applyContraintsToFollowers();
            this._endResize();
        },

        /**
         * Increase/decrease current dimension with adding values
         * @method resizeWith
         * @param {Number} w
         * @param {Number} h
         * */
        resizeWith: function (w, h) {
            this.dimension.resizeWith(w, h);
            this._applyContraintsToFollowers();
            this._endResize();
        },

        _endResize: function () {
            this._isDimensionChanged = true;
            this.invalidate();
            if (cgsgExist(this.onResize)) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_RESIZE, new CGSGEvent(this, {node: this}));
            }
        },

        /**
         * Replace current relative relativeScale by this new one
         * @method scaleTo
         * @param {Number} sx
         * @param {Number} sy
         * @param {Boolean} computeAbsoluteValue (default: true)
         * */
        scaleTo: function (sx, sy, computeAbsoluteValue) {
            this.scale.x = sx;
            this.scale.y = sy;
            if (this.needToKeepAbsoluteMatrix &amp;&amp; computeAbsoluteValue !== false) {
                this._absSca = this.getAbsScale(true);
            }

            this._applyContraintsToFollowers();

            if (cgsgExist(this.onScale)) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_SCALE, new CGSGEvent(this, {node: this}));
            }
        },

        /**
         * Multiply this relativeScale factor by the current relative relativeScale
         * @method scaleBy
         * @param {Number} sfx
         * @param {Number} sfy
         * @param {Boolean} computeAbsoluteValue (default: true)
         * */
        scaleBy: function (sfx, sfy, computeAbsoluteValue) {
            this.scale.x *= sfx;
            this.scale.y *= sfy;
            if (this.needToKeepAbsoluteMatrix &amp;&amp; computeAbsoluteValue !== false) {
                this._absSca = this.getAbsScale(true);
            }
            this._applyContraintsToFollowers();

            if (cgsgExist(this.onScale)) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_SCALE, new CGSGEvent(this, {node: this}));
            }
        },

        /**
         * Add to the current relative Scale
         * @method scaleWith
         * @param {Number} x
         * @param {Number} y
         * @param {Boolean} computeAbsoluteValue (default: true)
         * */
        scaleWith: function (x, y, computeAbsoluteValue) {
            this.scale.x += x;
            this.scale.y += y;
            if (this.needToKeepAbsoluteMatrix &amp;&amp; computeAbsoluteValue !== false) {
                this._absSca = this.getAbsScale(true);
            }
            this._applyContraintsToFollowers();

            if (cgsgExist(this.onScale)) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_SCALE, new CGSGEvent(this, {node: this}));
            }
        },

        /**
         * Replace current relative relativeRotation by this new oneScale
         * @method rotateTo
         * @param {Number} a
         * @param {Boolean} computeAbsoluteValue (default: true)
         *
         * */
        rotateTo: function (a, computeAbsoluteValue) {
            this.rotation.rotateTo(a);
            if (this.needToKeepAbsoluteMatrix &amp;&amp; computeAbsoluteValue !== false) {
                this._absRot = this.getAbsRotation(true);
            }
            this._applyContraintsToFollowers();

            if (cgsgExist(this.onRotate)) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_ROTATE, new CGSGEvent(this, {node: this}));
            }
        },

        /**
         * Multiply this relativeScale factor by the current relative relativeScale
         * @method rotateBy
         * @param {Number} af
         * @param {Boolean} computeAbsoluteValue (default: true)
         * */
        rotateBy: function (af, computeAbsoluteValue) {
            this.rotation.rotateBy(af);
            if (this.needToKeepAbsoluteMatrix &amp;&amp; computeAbsoluteValue !== false) {
                this._absRot = this.getAbsRotation(true);
            }
            this._applyContraintsToFollowers();

            if (cgsgExist(this.onRotate)) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_ROTATE, new CGSGEvent(this, {node: this}));
            }
        },

        /**
         * Add this angle to the current relative relativeRotation
         * @method rotateWith
         * @param {Number} a
         * @param {Boolean} computeAbsoluteValue (default: true)
         * */
        rotateWith: function (a, computeAbsoluteValue) {
            this.rotation.rotateWith(a);
            if (this.needToKeepAbsoluteMatrix &amp;&amp; computeAbsoluteValue !== false) {
                this._absRot = this.getAbsRotation(true);
            }

            this._applyContraintsToFollowers();
            if (cgsgExist(this.onRotate)) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_ROTATE, new CGSGEvent(this, {node: this}));
            }
        },

        //// CHILDREN MANIPULATION //////

        /**
         * Add a new nodes into this one, at the end of the list
         * @method addChild
         * @param {CGSGNode} newNode the nodes to add as a child
         * */
        addChild: function (newNode) {
            newNode._parentNode = this;
            this.children[this.children.length] = newNode;
        },

        /**
         * Add a new nodes at a particular index in the list of children.
         * If the index is too large, the nodes will be inserted at the end of the list
         * @method addChildAt
         * @param {CGSGNode} newNode the nodes to insert as a child
         * @param index {Number} index the position of the new child in the list
         * */
        addChildAt: function (newNode, i) {
            if (i &gt; this.children.length) {
                i = this.children.length;
            }

            for (var j = this.children.length; j &gt;= i; --j) {
                this.children[j] = this.children[j - 1];
            }

            newNode._parentNode = this;
            this.children[i] = newNode;

            if (cgsgExist(this.onChildAdd)) {
                CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_CHILD_ADD, new CGSGEvent(this, {node: this}));
            }
        },

        /**
         * Remove the child passed in parameter and delete it
         * @method removeChild
         * @param {CGSGNode} node the nodes to remove
         * @param {Boolean} searchRecursively if true, search the nodes on all the tree from this nodes
         * @return {Boolean} true if the child was correctly removed or false if the nodes was not found.
         * */
        removeChild: function (node, searchRecursively) {
            var index = this.children.indexOf(node);

            if (index &gt;= 0) {
                this.children.without(node);

                if (cgsgExist(this.onChildRemove)) {
                    CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_CHILD_REMOVED,
                                               new CGSGEvent(this, {node: this}));
                }
                node.free();

                return true;
            }

            if (searchRecursively) {
                for (var i = 0, len = this.children.length; i &lt; len; ++i) {
                    var childNode = this.children[i];
                    if (childNode.removeChild(node, true)) {
                        return true;
                    }
                }
            }

            return false;
        },

        /**
         * remove all children, delete them and reset the current parameters
         * @method removeAll
         * */
        removeAll: function () {
            /*for (var i = this.children.length; i &gt;=0; --i) {
             var childNode = this.children[i];
             childNode.removeAll();
             this.removeChild(childNode, true);
             }*/

            this.free();
        },

        /**
         * Detach the nodes in index &#x27;index&#x27; without delete it. So it&#x27;s not a child anymore
         * @method detachChildAt
         * @param i {Number} index
         */
        detachChildAt: function (i) {
            if (i &gt;= 0 &amp;&amp; i &lt; this.children.length) {
                this.detachChild(this.children[i]);
            }
        },

        /**
         * Detach the nodes without delete it. So it&#x27;s not a child anymore
         * @method detachChild
         * @param {CGSGNode} childNode
         */
        detachChild: function (childNode) {
            if (cgsgExist(childNode)) {
                childNode._parentNode = null;
                /*this.children = */
                this.children.without(childNode);
            }
        },

        /**
         * Execute/Eval the script passed in parameter in &quot;this&quot; scope.
         * Used to set new value to an attribute of a node
         * @method evalSet
         * @param a {String} attribute The attribute to be changed
         * @param v {*} value The new value for the attribute
         *
         * @example node.evalSet(&quot;position.y&quot;, 12);
         */
        evalSet: function (a, v) {
            var rgb;
            //check for common properties to optimize performances
            if (a === &quot;position.x&quot;) {
                this.translateTo(v, this.position.y, this.needToKeepAbsoluteMatrix);
            }
            else if (a === &quot;position.y&quot;) {
                this.translateTo(this.position.x, v, this.needToKeepAbsoluteMatrix);
            }
            else if (a === &quot;dimension.width&quot;) {
                this.resizeTo(v, this.dimension.height);
            }
            else if (a === &quot;dimension.height&quot;) {
                this.resizeTo(this.dimension.width, v);
            }
            else if (a === &quot;scale.x&quot;) {
                this.scaleTo(v, this.scale.y, this.needToKeepAbsoluteMatrix);
            }
            else if (a === &quot;scale.y&quot;) {
                this.scaleTo(this.scale.x, v, this.needToKeepAbsoluteMatrix);
            }
            else if (a === &quot;rotation&quot; || a === &quot;rotation.angle&quot;) {
                this.rotateTo(v, this.needToKeepAbsoluteMatrix);
            }
            else if (a === &quot;globalAlpha&quot; || a === &quot;opacity&quot;) {
                this.globalAlpha = v;
                this.invalidate();
            }
            else if (a === &quot;isVisible&quot;) {
                this.isVisible = v;
            }
            else if (a === &quot;rotationCenter.x&quot;) {
                this.rotationCenter.x = v;
            }
            else if (a === &quot;rotationCenter.y&quot;) {
                this.rotationCenter.y = v;
            }
            else if (a === &quot;bkgcolors[0].r&quot;) {
                rgb = CGSGColor.hex2rgb(this.bkgcolors[0]);
                this.bkgcolors[0] = CGSGColor.rgb2hex(v, rgb.g, rgb.b);
                this.invalidate();
            }
            else if (a === &quot;bkgcolors[0].g&quot;) {
                rgb = CGSGColor.hex2rgb(this.bkgcolors[0]);
                this.bkgcolors[0] = CGSGColor.rgb2hex(rgb.r, v, rgb.b);
                this.invalidate();
            }
            else if (a === &quot;bkgcolors[0].b&quot;) {
                rgb = CGSGColor.hex2rgb(this.bkgcolors[0]);
                this.bkgcolors[0] = CGSGColor.rgb2hex(rgb.r, rgb.g, v);
                this.invalidate();
            }
            else if (a === &quot;fillStyle.r&quot;) {
                this.fillStyle.r = v;
                this.invalidate();
            }
            else if (a === &quot;fillStyle.g&quot;) {
                this.fillStyle.g = v;
                this.invalidate();
            }
            else if (a === &quot;fillStyle.b&quot;) {
                this.fillStyle.b = v;
                this.invalidate();
            }

            //generic property
            else {
                eval(&quot;this.&quot; + a + &quot;=&quot; + v);
                this.invalidate();
            }

            /*if (this.needToKeepAbsoluteMatrix) {
             if (a.indexOf(&quot;position&quot;) === 0) {
             this._absPos = this.getAbsPosition(true);
             }
             else if (a.indexOf(&quot;rotation&quot;) === 0) {
             this._absRot = this.getAbsRotation(true);
             }
             else if (a.indexOf(&quot;scale&quot;) === 0) {
             this._absSca = this.getAbsScale(true);
             }
             }*/
        },

        /**
         * Set the region inside which one this node ca be placed an can move
         * @public
         * @method setRegionConstraint
         * @param {CGSGRegion} region a CGSGRegion relatively to this parent region. Can be null.
         */
        setRegionConstraint: function (region) {
            this.setNodeRegionConstraint(null);
            this.regionConstraint = region;
        },

        /**
         * Set the region inside which one this node ca be placed an can move
         * @public
         * @method setNodeRegionConstraint
         * @param node {CGSGNode} a CGSGNode relatively to this parent region. Can be null.
         */
        setNodeRegionConstraint: function (node) {
            this.regionConstraint = null;
            if (cgsgExist(node)) {
                if (!node._followers.contains(this)) {
                    node._followers.push(this);
                }
            }
            else if (cgsgExist(this.nodeConstraint)) {
                this.nodeConstraint._followers.without(this);
            }

            this.nodeConstraint = node;
        },

        /**
         * @public
         * @method getAbsPosition
         * @param {boolean} recursive flag indicating if computation should be recusive or not
         * @return {CGSGPosition} the absolute positions of this node
         */
        getAbsPosition: function (recursive) {
            var n = this;
            var translation = this.position.copy();
            while (n._parentNode !== null) {
                translation.multiplyEquals(n._parentNode.scale);
                n = n._parentNode;
            }

            if (this._parentNode !== null) {
                translation.addEquals(this._parentNode.getAbsPosition(false));
            }

            if (recursive !== false) {
                for (var c = 0; c &lt; this.children.length; c++) {
                    if (cgsgExist(this.children[c])) {
                        this.children[c]._absPos = this.children[c].getAbsPosition(recursive);
                    }
                }
            }

            return translation;
        },

        /**
         * @public
         * @method getAbsScale
         * @param {boolean} recursive flag indicating if computation should be recusive or not
         * @return {CGSGScale} the absolute scale of this node
         */
        getAbsScale: function (recursive) {
            var n = this;
            var s = this.scale.copy();
            while (n._parentNode !== null) {
                s.multiplyEquals(n._parentNode.scale);
                n = n._parentNode;
            }

            if (recursive !== false) {
                for (var c = 0; c &lt; this.children.length; c++) {
                    if (cgsgExist(this.children[c])) {
                        this.children[c]._absSca = this.children[c].getAbsScale(recursive);
                    }
                }
            }
            return s;
        },

        /**
         * @public
         * @method getAbsRotation
         * @param {boolean} recursive flag indicating if computation should be recusive or not
         * @return {CGSGRotation} the absolute rotation of this node
         */
        getAbsRotation: function (recursive) {
            var n = this;
            var r = this.rotation.copy();
            while (n._parentNode !== null) {
                r.addEquals(n._parentNode.rotation.angle);
                n = n._parentNode;
            }

            if (recursive !== false) {
                for (var c = 0; c &lt; this.children.length; c++) {
                    if (cgsgExist(this.children[c])) {
                        this.children[c]._absRot = this.children[c].getAbsRotation(recursive);
                    }
                }
            }

            return r;
        },

        /**
         * Compute the absolute position, rotation and scale in the canvas container
         * @public
         * @method computeAbsoluteMatrix
         * @param {Boolean} recursive if !== false, compute recursively
         * */
        computeAbsoluteMatrix: function (recursive) {
            this._absPos = this.getAbsPosition(false);
            this._absSca = this.getAbsScale(false);
            this._absRot = this.getAbsRotation(false);

            if (recursive !== false) {
                //for (var c = 0; c &lt; this.children.length; c++) {
                cgsgIterate(this.children, (function (i, child) {
                    if (cgsgExist(child)) {
                        child.computeAbsoluteMatrix(recursive);
                    }
                }).bind(this));
                //}
            }
        },

        /**
         * Returns the x position with the lowest value between this node and its children.
         *
         * @method getMinAbsoluteLeft
         * @return {Number}
         */
        getMinAbsoluteLeft: function () {
            var retval = this._absPos.x;

            if (this.children.length &gt; 0) {
                cgsgIterate(this.children.length, (function (i, child) {
                    if (retval &lt; child._absPos.x) {
                        retval = child._absPos.x;
                    }
                }).bind(this));
            }

            return retval;
        },

        /**
         * Returns the right border&#x27;s position with the highest value between this node and its children.
         *
         * @method getMostAbsoluteRight
         * @return {Number}
         */
        getMaxAbsoluteRight: function () {
            var retval = this._absPos.x + (this.getWidth() * this._absSca.x);

            if (this.children.length &gt; 0) {
                cgsgIterate(this.children.length, (function (i, child) {
                    var absRight = this._absPos.x + (this.getWidth() * this._absSca.x);
                    if (retval &lt; absRight) {
                        retval = absRight;
                    }
                }).bind(this));
            }

            return retval;
        },

        /**
         * Returns the y position with the lowest value between this node and its children.
         *
         * @method getMinAbsoluteTop
         * @return {Number}
         */
        getMinAbsoluteTop: function () {
            var retval = this._absPos.y;

            if (this.children.length &gt; 0) {
                cgsgIterate(this.children.length, (function (i, child) {
                    if (retval &lt; child._absPos.y) {
                        retval = child._absPos.y;
                    }
                }).bind(this));
            }

            return retval;
        },

        /**
         * Returns the bottom border&#x27;s position with the highest value between this node and its children.
         *
         * @method getAbsBottom
         * @return {Number}
         */
        getMaxAbsoluteBottom: function () {
            var retval = this._absPos.y + (this.getHeight() * this._absSca.y);

            if (this.children.length &gt; 0) {
                cgsgIterate(this.children.length, (function (i, child) {
                    var absRight = this._absPos.y + (this.getHeight() * this._absSca.y);
                    if (retval &lt; absRight) {
                        retval = absRight;
                    }
                }).bind(this));
            }

            return retval;
        },
        /**
         *
         * @method getAbsLeft
         * @return {Number}
         */
        getAbsLeft          : function () {
            return this._absPos.x;
        },

        /**
         * @method getAbsRight
         * @return {Number}
         */
        getAbsRight: function () {
            return this._absPos.x + this.getAbsWidth();
        },

        /**
         * @method getAbsTop
         * @return {Number}
         */
        getAbsTop: function () {
            return this._absPos.y;
        },

        /**
         * @method getAbsBottom
         * @return {Number}
         */
        getAbsBottom: function () {
            return this._absPos.y + this.getAbsHeight();
        },

        /**
         * @method getAbsWidth
         * @return {Number}
         */
        getAbsWidth: function () {
            return this.getWidth() * this._absSca.x;
        },

        /**
         * @method getAbsHeight
         * @return {Number}
         */
        getAbsHeight: function () {
            return this.getHeight() * this._absSca.y;
        },

        /**
         * @method getWidth
         * @return {Number}
         */
        getWidth: function () {
            return this.dimension.width;
        },

        /**
         * @method getHeight
         * @return {Number}
         */
        getHeight: function () {
            return this.dimension.height;
        },

        /**
         * Return center of the node, based on its position and dimension
         * @method getCenter
         * @return {CGSGPosition}
         */
        getCenter: function () {
            var x = this.position.x + (this.getWidth() / 2);
            var y = this.position.y + (this.getHeight() / 2);

            return new CGSGPosition(x, y);
        },

        /**
         * Test if this node is colliding the node in parameter. Don&#x27;t forget to add nodes to CGSGCollisionManager.
         *
         * @public
         * @method isColliding
         * @return {Boolean} true if the 2 nodes are colliding. They are colliding if the distance between them is minus than the threshold parameter
         * @param {CGSGNode} node a CGSGNode
         * @param {Number} threshold space between the 2 nodes before considering they are colliding
         */
        isColliding: function (node, threshold) {
            return CGSG.collisionManager.isColliding(this, node, threshold);
        },

        /**
         * @public
         * @method getListOfCollidingBrothers
         * @return {Array} a Array of nodes this one is colliding with (can be empty)
         * @param {Number} threshold space between the 2 nodes before considering they are colliding
         */
        getListOfCollidingBrothers: function (threshold) {
            var listOfCollidingNodes = [];
            var brother = null;
            //for (var n = 0; n &lt; this._parentNode.children.length; n++) {
            cgsgIterate(this._parentNode.children, (function (i, brother) {
                if (brother !== this &amp;&amp; this.isColliding(brother, threshold)) {
                    listOfCollidingNodes.push(brother);
                }
            }).bind(this));
            //}

            return listOfCollidingNodes;
        },

        /**
         * @public
         * @method isCollidingABrother
         * @param {Number} threshold space between the 2 nodes before considering they are colliding
         * @return {Boolean} true if this node is colliding one of the other children of its parent node
         */
        isCollidingABrother: function (threshold) {
            var retval = false;

            cgsgIterate(this._parentNode.children, (function (i, brother) {
                if (brother !== this &amp;&amp; this.isColliding(brother, threshold)) {
                    retval = true;

                    return retval; // break the loop
                }
                return false;
            }).bind(this));

            return retval;
        },

        /*
         * TODO : to be completed
         * Return the list of lines going joigning nodes&#x27; peaks
         * param onlyBrothers a Boolean. Default = true
         * param threshold distance from which the detectection is done
         * return an array of CGSGVector2D (can be empty)
         */
        /*getMagneticLines : function(onlyBrothers, threshold) {
         if (!cgsgExist(onlyBrothers)) {
         onlyBrothers = true;
         }

         //compute vectors
         var topVector = this.getAbsTop();
         var bottomVector = this.getAbsBottom();
         var leftVector = this.getAbsLeft();
         var rightVector = this.getAbsRight();

         //line = a point and a normalized CGSGVector2D (ie : [0, 1] or [1, 0])
         var listOfLines = [];

         var brother = null;
         for (var n = 0; n &lt; this._parentNode.children.length; n++) {
         brother = this._parentNode.children[n];

         //vectors v &amp; v&#x27; are colinear if and only if xy’ - yx’ = 0.

         }

         return listOfLines;
         },*/

        /**
         * Must be overrided by inherited classes
         * @method copy
         * @param {CGSGNode} node
         * @return {CGSGNode} a copy of this node
         */
        copy: function (node) {
            if (node === null || node === undefined) {
                node = new CGSGNode(this.position.x, this.position.y);
                node.resizeTo(this.dimension.width, this.dimension.height);
            }
            node.classType = this.classType;
            node.name = this.name;
            node.globalAlpha = this.globalAlpha;
            node.bkgcolors = this.bkgcolors;
            node.lineColor = this.lineColor;
            node.lineWidth = this.lineWidth;
            node.isVisible = this.isVisible;
            node.isProportionalResize = this.isProportionalResize;
            node.pickNodeMethod = this.pickNodeMethod;
            node.needToKeepAbsoluteMatrix = this.needToKeepAbsoluteMatrix;

            //list of the children (empty if this nodes is a leaf)
            //this.children = [];

            if (this.regionConstraint !== null) {
                node.regionConstraint = this.regionConstraint.copy();
            }
            node.nodeConstraint = this.nodeConstraint;

            //can be fulfilled by the developer to put in whatever he needs
            node.userData = this.userData;

            //selection attributes
            //if true, this nodes is clickable and so will be checked by the pickNode function
            node.isClickable = this.isClickable;
            //if true, this nodes can be selected and so can be transformed (dimension)
            node.isResizable = this.isResizable;
            node.isDraggable = this.isDraggable;
            node.isTraversable = this.isTraversable;

            node.selectionLineColor = this.selectionLineColor;
            node.selectionLineWidth = this.selectionLineWidth;
            node.handleSize = this.handleSize;
            node.handleColor = this.handleColor;
            node._id = this._id;
            node.translateTo(this.position.x, this.position.y);
            node.resizeTo(this.dimension.width, this.dimension.height);
            node.scaleTo(this.scale.x, this.scale.y);
            node.rotateTo(this.rotation.angle);

            //node.selectableZone =
            //new CGSGRegion(node.position.x, node.position.y, node.dimension.width, node.dimension.height);

            //all the events for the node
            node.onMouseOver = this.onMouseOver;
            node.onMouseOut = this.onMouseOut;
            node.onClick = this.onClick;
            node.onDblClick = this.onDblClick;
            node.onDrag = this.onDrag;
            node.onDragEnd = this.onDragEnd;
            node.onResize = this.onResize;
            node.onResizeEnd = this.onResizeEnd;
            node.onSelect = this.onSelect;
            node.onDeselect = this.onDeselect;

            node.computeAbsoluteMatrix(true);

            return node;
        },

        /**
         * free memory taken by this object and it&#x27;s children.
         * The &#x27;userData&#x27; property won&#x27;t be freed
         * @method free
         */
        free: function () {
            for (var c = this.children.length - 1; c &gt;= 0; c--) {
                this.children[c].free();
            }

            this.children.clear();

            cgsgFree(this);
        }
    }
)
    ;
    </pre>
</div>

                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<script src="../assets/vendor/prettify/prettify-min.js"></script>
<script>prettyPrint();</script>
<script src="../assets/js/yui-prettify.js"></script>
<script src="../assets/../api.js"></script>
<script src="../assets/js/api-filter.js"></script>
<script src="../assets/js/api-list.js"></script>
<script src="../assets/js/api-search.js"></script>
<script src="../assets/js/apidocs.js"></script>
</body>
</html>
